#include "zydl_cut.h"

#include<tool/libcell_tools_formats.h>
#include<tool/libcell_tools_view.h>
#include "subdivision_of_polygon.h"
#include "intersection_of_two_polygons.h"
#include "intersection_curve_of_two_surfaces.h"
#include "intersection_remesh_and_cut.h"
#include<Mesh/libcell_iterator.h>
#include<Mesh/Mesh_Operator.h>
#include<export_obj.h>
#include<libcell_macros.h>
#include "directories_and_files.h"


// static void test_show_mesh_cells_from_node(Viewer_World*vw,Node*node)
// {
//     Node* n=vw->create_something(vw,"Faces");
//     Viewer_Something* vs=(Viewer_Something*)(n->value);
//     Viewer_Faces*vf=(Viewer_Faces*)(vs->evolution);
//     vf->Data_index_rows=node_size(node);
//     Int_RB_Tree* tree=(Int_RB_Tree*)malloc(sizeof(Int_RB_Tree));
//     int_rb_tree_init(tree);
//     int f_size=0, i=0;
//     for(Node* nit=node;nit!=NULL;nit=(Node*)(nit->Next))
//     {
//         template_c* c=(template_c*)(nit->value);
//         f_size+=c->vertices_size+1;
//         for(int j=0;j<c->vertices_size;j++)
//         {
//             if(tree->find(tree,c->vertices[j]->id)==NULL)
//             {
//                 int * value=(int*)malloc(sizeof(int));
//                 *value=i;
//                 tree->insert(tree,c->vertices[j]->id,value);
//                 i++;
//             }
//         }
//     }
//     vf->Data_index=(unsigned int*)malloc(sizeof(unsigned int)*f_size);
//     vf->Data_rows=i; 
//     vf->Data=(float*)malloc(sizeof(float)*3*vf->Data_rows);

//     i=0;
//     for(Node* nit=node;nit!=NULL;nit=(Node*)(nit->Next))
//     {
//         template_c* c=(template_c*)(nit->value);
//         vf->Data_index[i]=c->vertices_size;
//         i++;
//         for(int j=0;j<c->vertices_size;j++)
//         {
//             vf->Data_index[i]=*((int*)(tree->find(tree,c->vertices[j]->id)));
//             int k=vf->Data_index[i];
//             vf->Data[k*3+0]=c->vertices[j]->point[0];vf->Data[k*3+1]=c->vertices[j]->point[1];vf->Data[k*3+2]=c->vertices[j]->point[2];
             
//             i++;  
//         } 
//     }    
//     int_rb_tree_free_value(tree);
//     int_rb_tree_free(tree);

//     vf->color_rows=vf->Data_index_rows;
//     vf->set_color(vf,0.7,0.6,0.7,1.0);

//     vf->normal_rows=vf->Data_index_rows;
//     vf->compute_normal(vf);

//     free_node(n);
// }

// static void test_show_mesh_cells_from_mesh(Viewer_World* vw,Mesh*m)
// {
//     Node* n=vw->create_something(vw,"Faces");
//     Viewer_Something*vs=(Viewer_Something*)(n->value);
//     Viewer_Faces* vf=(Viewer_Faces*)(vs->evolution);
     
//     vf->Data_rows=m->num_v(m);
//     vf->Data_index_rows=m->num_c(m);
//     get_data_from_2dim_cell(m,&(vf->Data),&(vf->Data_index));
    
    
//     vf->color_rows=vf->Data_index_rows;
//     vf->set_color(vf,0.4,0.6,0.7,1.0);

//     vf->normal_rows=vf->Data_index_rows;
//     vf->compute_normal(vf);
    
//     free_node(n); 

// }

static int is_point_in_polygon(double*p,double**ps,int len,int** s )
{
    for(int i=0;i<len-2;i++)
    {
        if(is_point_in_triangle(p,ps[s[i][0]],ps[s[i][1]],ps[s[i][2]]));
        {
            return 1; 
        } 
    }
    return 0;
}
static int is_cell_in_polygon(Mesh*m,template_c*c,double**ps,int len,int** s)
{
    for(auto cvit=m->cv_begin(m,*c);cvit!=m->cv_end(m,*c);cvit++)
    {   
        if(is_point_in_polygon(quote(cvit)->point,ps,len,s)==0)
        {
            return 0;
        }
    } 
    return 1;
}


static inline template_c* mytest_m_find_first_cell(Mesh*m,double** ps,int len,Node* exept_ns)
{
    if(m==NULL||m->num_c(m)<=0)
    {
        return NULL;
    }
    int **s=(int**)malloc(sizeof(int*)*(len-2));
    for(int i=0;i<len-2;i++)
    {
        s[i]=(int*)malloc(sizeof(int)*3); 
        memset(s[i],0,sizeof(int)*3);
    } 
    optimization_subdivision_of_polygon(ps,len,s); 
    template_c* re=NULL;
    for(auto cit=m->c_begin(m);cit!=m->c_end(m);cit++)
    {
        if(is_cell_in_polygon(m,quote(cit),ps,len,s)==1&&node_find(exept_ns,quote(cit))==NULL)
        {
            re=quote(cit); 
            break;
        } 
    } 
    for(int i=0;i<len-2;i++)
    {
        free(s[i]);
    }
    free(s);

    return re;
}

static Node* get_cells_in_polygon_areas(Mesh* m,double**ps,int len )
{
    Node* re=NULL;

    int **s=(int**)malloc(sizeof(int*)*(len-2));
    for(int i=0;i<len-2;i++)
    {
        s[i]=(int*)malloc(sizeof(int)*3); 
        memset(s[i],0,sizeof(int)*3);
    } 
    optimization_subdivision_of_polygon(ps,len,s); 

    for(auto cit=m->c_begin(m);cit!=m->c_end(m);cit++)
    {
        if(is_cell_in_polygon(m,quote(cit),ps,len,s)==1)
        {
            re=node_overlying(re,quote(cit));
        }
    } 
    for(int i=0;i<len-2;i++)
    {
        free(s[i]);
    }
    free(s);
    return re;
}

static Node*  mytest_m(Mesh* m,double**ps,int len,Node* exept_ns)
{
    //printf("m num c:%d\n",m->num_c(m));
    Node* re=NULL,*node1=NULL; 
    template_c* c=mytest_m_find_first_cell(m,ps,len,exept_ns);
    if(c==NULL)
    {
        printf("first cell is NULL %d\n",m->num_c(m));
        return re;
    }
    Int_RB_Tree* tree=(Int_RB_Tree*)malloc(sizeof(Int_RB_Tree));
    int_rb_tree_init(tree);
    re=node_overlying(re,c);
    node1=node_overlying(node1,c);
    int flag=1;
    tree->insert(tree,c->id,&flag);
    while(node1!=NULL)
    {
        Node* temp_n=NULL;
        for(Node* nit=node1;nit!=NULL;nit=(Node*)(nit->Next))
        {
            c=(template_c*)(nit->value);
            for(auto chfit=m->chf_begin(m,*c);chfit!=m->chf_end(m,*c);chfit++)
            {
                template_c* c1=m->s_opposite_halfface(quote(chfit))->cell;
                if(c1!=NULL&&tree->find(tree,c1->id)==NULL)
                {
                    temp_n=node_overlying(temp_n,c1);
                    re=node_overlying(re,c1);
                    tree->insert(tree,c1->id,&flag);
                }
            }
        } 
        free_node(node1);
        node1=temp_n;
    }
    printf("here\n");
    int_rb_tree_free(tree);

    return re;
}
static Node* find_connect_cells1(Mesh*m,Int_RB_Tree*tree,template_c*c)
{
    Node* re=NULL,*node1=NULL; 
    if(c==NULL)
    {
        printf("first cell is NULL ");
        return re;
    }
    Int_RB_Tree* tree1=(Int_RB_Tree*)malloc(sizeof(Int_RB_Tree));
    int_rb_tree_init(tree1);
    re=node_overlying(re,c);
    node1=node_overlying(node1,c);
    int flag=1;
    tree1->insert(tree1,c->id,&flag);
    tree->erase(tree,c->id);
    while(node1!=NULL)
    {
        Node* temp_n=NULL;
        for(Node* nit=node1;nit!=NULL;nit=(Node*)(nit->Next))
        {
            template_c*c2=(template_c*)(nit->value);
            for(auto chfit=m->chf_begin(m,*c2);chfit!=m->chf_end(m,*c2);chfit++)
            {
                template_c* c1=m->s_opposite_halfface(quote(chfit))->cell;
                if(c1!=NULL&&tree1->find(tree1,c1->id)==NULL)
                {
                    temp_n=node_overlying(temp_n,c1);
                    re=node_overlying(re,c1);
                    tree1->insert(tree1,c1->id,&flag);
                    tree->erase(tree,c1->id);
                }
            }
        } 
        free_node(node1);
        node1=temp_n;
    }
    printf("here\n");
    int_rb_tree_free(tree1);
    return re;
}
static Node* mytest_m1(Mesh* m,double**ps,int len)
{
    Node*re=NULL;
    int **s=(int**)malloc(sizeof(int*)*(len-2));
    for(int i=0;i<len-2;i++)
    {
        s[i]=(int*)malloc(sizeof(int)*3); 
        memset(s[i],0,sizeof(int)*3);
    } 
    optimization_subdivision_of_polygon(ps,len,s); 
    Int_RB_Tree*tree=(Int_RB_Tree*)malloc(sizeof(Int_RB_Tree));
    int_rb_tree_init(tree); 
    for(auto cit=m->c_begin(m);cit!=m->c_end(m);cit++)
    {
        if(is_cell_in_polygon(m,quote(cit),ps,len,s)==1)
        {
            tree->insert(tree,quote(cit)->id,quote(cit));
        }
    }
    // do
    // {


    // }while(size1-size>size2*0.8);
    int len1=tree->size;
    while(tree->size>0)
    {

        int size=tree->size;

        auto it=tree->begin(tree);

        template_c* c=(template_c*)(it.second);

        Node* connect_cells=find_connect_cells1(m,tree,c);
        int size1=tree->size;
        int size2=node_size(connect_cells);
        if(size-size1>0.9*size2&&size2>=len1*0.4)
        {
            Node* rever=node_reverse(connect_cells);
            rever->Next=re;
            if(re!=NULL)
            {
                re->Prev=rever;
            }
            re=connect_cells;
        } 
        else
        {
            free_node(connect_cells);
        }
        printf("size1:%d size2:%d size:%d\n",size1,size2,size);
    }  
    //re=connect_cells;
    int_rb_tree_free(tree);
    for(int i=0;i<len-2;i++)
    {
        free(s[i]);
    }
    free(s);
    return re; 
}
// 中原动力的测试函数
void export_cut_result(Mesh* m,double **ps,int len,char*outfilename )
{
    Node* n1=NULL,*n2=NULL;
    // printf("begin\n"); 
    for(auto it=m->c_begin(m);it!=m->c_end(m);it++)
    {
        n1=node_overlying(n1,quote(it));
    } 
    Mesh m1;
    Mesh_init(&m1);
   // printf("here\n");
    double **V=(double**)malloc(sizeof(double*)*len*2);
    for(int i=0;i<len;i++)
    {
        V[i]=(double*)malloc(sizeof(double)*3);
        V[i][0]=ps[i][0];V[i][1]=ps[i][1];V[i][2]=-210.0;
        V[i+len]=(double*)malloc(sizeof(double)*3);
        V[i+len][0]=ps[i][0];V[i+len][1]=ps[i][1];V[i+len][2]=150.0; 
    }
    int ** C=(int**)malloc(sizeof(int*)*len*2);
    for(int i=0;i<len;i++)
    {
        C[2*i+0]=(int*)malloc(sizeof(int)*4);
        C[2*i+0][0]=3;
        C[2*i+0][1]=i;C[2*i+0][2]=(i+1)%len;C[2*i+0][3]=i+len;
/////***********************
        C[2*i+1]=(int*)malloc(sizeof(int)*4);
        C[2*i+1][0]=3;
        C[2*i+1][1]=(i+1)%len+len;C[2*i+1][2]=i+len;C[2*i+1][3]=(i+1)%len;
    }

    int nums[3]={len*2,0,len*2};
    _ReadArray_(&m1,V,NULL,C,nums,3,2);

    for(int i=0;i<len;i++)
    {
        free(V[i]);free(V[i+len]);
        free(C[i*2+0]);free(C[i*2+1]);
    }
    free(V);free(C);
   
    for(auto it=m1.c_begin(&m1);it!=m1.c_end(&m1);it++)
    {
        n2=node_overlying(n2,quote(it));
    } 


    printf("n1 size:%d\n",node_size(n1));
    int flag=0;
    Node* nn1=simplify_node_of_two_nodes(n2,n1,&flag);
    printf("nn1 size:%d\n",node_size(nn1));
    printf("begin\n");
   
    // export_obj_from_node(nn1,"test.obj","texture_BA.mtl");
    // export_obj_from_node(nn1,"test.obj",NULL);
    Mesh2_Crossover_Point* mcp1=(Mesh2_Crossover_Point*)malloc(sizeof(Mesh2_Crossover_Point));
    Mesh2_Crossover_Point* mcp2=(Mesh2_Crossover_Point*)malloc(sizeof(Mesh2_Crossover_Point));
    mesh2_crossover_point_init(mcp1);mesh2_crossover_point_init(mcp2);

    Mesh* m3=get_intersection_lines_of_two_nodesn(nn1,n2,mcp1,mcp2);

    adjust_mesh_topology(m3,mcp1,mcp2);

    //测试重新mesh后的区域
    // printf("测试;%d %d\n",mcp1->c2p->size,m1.num_f(&m1));
    Int_RB_Tree* tree=(Int_RB_Tree*)malloc(sizeof(Int_RB_Tree)),*tree1=(Int_RB_Tree*)malloc(sizeof(Int_RB_Tree));
    int_rb_tree_init(tree);int_rb_tree_init(tree1);
    printf("remesh\n");
    Mesh* m5=my_intersection_remesh(nn1,mcp1,m3,tree,tree1);
    printf("cut\n");

    my_intersection_cut(m5,m3,tree,tree1); 
    printf("texuter\n");
    my_chuli_texture(m5,m,tree1);
    printf("connec_cells\n");
    //Node* connec_cells=get_cells_in_polygon_areas(m5,ps,len);
    //Node* connec_cells=mytest_m(m5,ps,len,NULL);
    Node* connec_cells=mytest_m1(m5,ps,len);


    printf("expot obj\n");

    // export_obj_from_mesh(m5,"test.obj");

    OBJ_MESH_PROP* omp=(OBJ_MESH_PROP*)(m->prop);
    printf("%s\n",omp->mtlibname); 
    export_obj_from_node(connec_cells,outfilename,omp->mtlibname);
    // if(connec_cells==NULL)
    // {
    //     remove(outfilename);
    // }
    //printf("m5 size1 :%d size2:%d %d\n",node_size(nn1),tree1->size,m5->num_c(m5)); 
    //mytest_m(m5);
    //printf("m5 numc:%d\n"m5->num_c(m5));
    int_rb_tree_free(tree1);
    int_rb_tree_free(tree); 
    printf("可视化\n");

    

// 可视化
    // Viewer_World_Manager vwm;
    // viewer_world_manager_init(&vwm);

    // Viewer_World *vw=vwm.create_world(&vwm,NULL);

    // add_default_somethings(vw);
    // // m3*0.00001;
    // // (*m5)*0.00001; 
    // // test_show_mesh_lines(vw,m3);
    // test_show_mesh_cells_from_mesh(vw,&m1);
    // test_show_mesh_cells_from_node(vw,nn1);
    // // my_test_show_cat_mesh_cells(vw,&obj_mesh);

   // test_show_mesh_lines(vw,&m1);

    // // Mesh m6;
    // // Mesh_init(&m6);
    // // _ReadOff_(&m6,"texture_BA.off",3);
    // // test_show_mesh_cells(vw,&m6);
    // // Mesh_free(&m6);
    // //get_intersection_lines_of_two_nodesn(n1,n2,m);
    // Viewer_Opengl_Interpreter voi;
    // viewer_opengl_interpreter_initn(&voi,&vwm);
    // voi.interpreter(&voi);
    // viewer_opengl_interpreter_free(&voi);
    // viewer_world_manager_free(&vwm);
//可视化


    Mesh_free(&m1);
    for(auto it=mcp1->c2p->begin(mcp1->c2p);it.it!=NULL;it++)
    {
        free_node(((Node*)(it.second)));
    }
    for(auto it=mcp1->f2p->begin(mcp1->f2p);it.it!=NULL;it++)
    {
        free_node(((Node*)(it.second)));
    }
    for(auto it=mcp2->c2p->begin(mcp2->c2p);it.it!=NULL;it++)
    {free_node(((Node*)(it.second)));}
    for(auto it=mcp2->f2p->begin(mcp2->f2p);it.it!=NULL;it++)
    {free_node(((Node*)(it.second)));}
    mesh2_crossover_point_free(mcp1);mesh2_crossover_point_free(mcp2);
    free_node(n1);free_node(n2);free_node(nn1);free_node(connec_cells);
    //m3 
    for(auto vit=m3->v_begin(m3);vit!=m3->v_end(m3);vit++)
    {
        SAFE_FREE(quote(vit)->prop);
    }
    Mesh_free(m3);
    free(m3);
    //m5
    SAFE_FREE(m5->prop);
    for(auto cit=m5->c_begin(m5);cit!=m5->c_end(m5);cit++)
    {
        SAFE_FREE(quote(cit)->prop);
    }
    Mesh_free(m5);
    free(m5);
}
int  tailing_test(char* mesh_path,char* out_path,double**ps,int len)
{
    Mesh mesh;
    Mesh_init(&mesh); 

    _ReadObj_(&mesh,mesh_path);
    
    export_cut_result(&mesh,ps,len,out_path); 
    printf("end export cut result\n");
    for(auto cit=mesh.c_begin(&mesh);cit!=mesh.c_end(&mesh);cit++)
    {
        SAFE_FREE(quote(cit)->prop);
    }
    SAFE_FREE(mesh.prop);
    Mesh_free(&mesh);

    printf("endhere\n");
    return 1;
}

void zydl_test(char*path,double**ps,int len)
{
    int count_files=0;
    char** files=search_dir_files(path,&count_files);
    for(int i=0;i<count_files;i++)
    {
        int temp_len=strlen(files[i]);
        if(temp_len>4&&files[i][temp_len-1]=='j'&&files[i][temp_len-2]=='b'&&files[i][temp_len-3]=='o'&&files[i][temp_len-4]=='.') 
        {
            char file[200]={0};
            strcat(file,path);
            strcat(file,"/");
            strcat(file,files[i]);

            printf("%s\n",file); 
            Mesh mesh;
            Mesh_init(&mesh);
            _ReadObj_(&mesh,file);
            char outfile[200]={0};
            strcat(outfile,path);
            strcat(outfile,"/");
            strcat(outfile,files[i]);
             
            export_cut_result(&mesh,ps,len,file);

            for(auto cit=mesh.c_begin(&mesh);cit!=mesh.c_end(&mesh);cit++)
            {
                SAFE_FREE(quote(cit)->prop);
            }

            Mesh_free(&mesh);
            SAFE_FREE(mesh.prop);
        }
    } 

    for(int i=0;i<count_files;i++)
    {
        free(files[i]);
    }
    free(files);
}
